import 'package:ylm_ui_kit/ylm_ui_kit.dart';

///处理json
typedef DecodeJson<T> = T Function(String json);

///进度
typedef CommonProgress = void Function(int count, int total);

///用于具体接口需要单独处理的错误
class CommonNetOtherError implements Exception {
  CommonNetOtherError({this.code, this.msg});

  final int? code;
  final String? msg;

  @override
  String toString() => "Exception";
}

///错误类型
enum CommonNetError {
  ///链接超时
  connectTimeout,

  ///接收超时
  receiveTimeout,

  ///发送超时
  sendTimeout,

  ///取消
  cancel,

  ///网络错误，没有链接等
  netError,

  ///数据解析失败
  formatError,

  ///其他
  other,
}

///配置网络的基本参数
abstract class CommonNetBuilder {
  String getBaseUrl();

  Future<Map<String, dynamic>> initHeaders();

  Future<Map<String, dynamic>> initAutoPostParams();

  Future<dynamic> reduceJson(dynamic jsonStr);

  void showError(CommonNetError errorType, Exception error);

  void print(dynamic msg);
}

///请求的框架的接口
abstract class CommonNetSkeleton {
  Future init(CommonNetBuilder commonNetBuilder);

  Future release();

  CommonNetError reduceError(dynamic e);

  Future refreshHeader();

  Future<dynamic> commonGet(CommonApi api, {String? baseUrl, String? contentType});

  Future<dynamic> commonPost(CommonApi api, {String? baseUrl, String? contentType});

  Future<dynamic> commonUpload(
    CommonUploadApi api, {
    CommonProgress? progress,
    String? baseUrl,
    String? contentType,
  });

  Future<dynamic> commonDownload(
    CommonDownloadApi api, {
    CommonProgress? progress,
    String? baseUrl,
    String? contentType,
  });

  ///对于没有封装的调用，可临时使用这个，之后支持
  Future<dynamic> unSupport(
    dynamic api, {
    CommonProgress? progress,
    String? baseUrl,
  });
}

///请求参数
abstract class CommonApi {
  CommonApi(this.api, {Map<String, dynamic>? params}) {
    if (params == null) {
      this.params = {};
    } else {
      this.params = params;
    }
  }

  final String api;
  late final Map<String, dynamic> params;
}

///请求参数-上传文件
abstract class CommonUploadApi extends CommonApi {
  CommonUploadApi(
    String api,
    this.uploadFileParamsName,
    this.filePaths,
    this.mediaType, [
    Map<String, dynamic>? params,
  ]) : super(api, params: params);

  final String uploadFileParamsName;
  final List<String> filePaths;
  final String mediaType;
}

///请求参数-下载文件
class CommonDownloadApi extends CommonApi {
  CommonDownloadApi(String api, this.saveFilePath) : super(api);

  final String saveFilePath;
}

///请求的逻辑
class CommonNet {
  CommonNet._inner();

  static final CommonNet _instance = CommonNet._inner();

  factory CommonNet() => _instance;

  CommonNetSkeleton? _net;
  CommonNetBuilder? _commonNetBuilder;

  static CommonNetSkeleton get skeleton => _instance._net!;
  static CommonNetBuilder get builder => _instance._commonNetBuilder!;

  ///初始化
  Future init(
    CommonNetSkeleton commonNetSkeleton,
    CommonNetBuilder commonNetBuilder,
  ) async {
    if (_net != null) {
      await _net!.release();
    }
    _net = commonNetSkeleton;
    _commonNetBuilder = commonNetBuilder;
    await _net!.init(_commonNetBuilder!);
  }

  ///刷新token
  static Future refreshHeader() {
    return _instance._net!.refreshHeader();
  }

  ///设置请求参数
  static Future<dynamic> _setAutoParams(CommonApi api) async {
    var autoParams = await _instance._commonNetBuilder?.initAutoPostParams();
    if (autoParams != null && autoParams.isNotEmpty) {
      api.params.addAll(autoParams);
    }
  }

  ///网络请求
  static Future<dynamic> _doNet(Future Function() task) async {
    try {
      return await task();
    } catch (e) {
      Loading.dismiss();
      _instance._commonNetBuilder?.print(e);
      CommonNetError error = _instance._net!.reduceError(e);
      if (error != CommonNetError.other && e is FormatException) {
        _instance._commonNetBuilder?.showError(CommonNetError.formatError, e);
      } else {
        if (e is CommonNetOtherError) rethrow;
        _instance._commonNetBuilder?.showError(error, e as Exception);
      }
      rethrow;
    }
  }

  static Future<dynamic> get(CommonApi api, {String? baseUrl, String? contentType}) async {
    return await _doNet(() async {
      await _setAutoParams(api);
      dynamic json = await _instance._net!.commonGet(api, baseUrl: baseUrl, contentType: contentType);
      return await _instance._commonNetBuilder!.reduceJson(json);
    });
  }

  static Future<dynamic> post(CommonApi api, {String? baseUrl, String? contentType}) async {
    return await _doNet(() async {
      await _setAutoParams(api);
      dynamic json = await _instance._net!.commonPost(api, baseUrl: baseUrl, contentType: contentType);
      return await _instance._commonNetBuilder!.reduceJson(json);
    });
  }

  static Future<dynamic> upload(
    CommonUploadApi api, {
    CommonProgress? progress,
    bool reduceError = true,
    String? baseUrl,
    String? contentType,
  }) async {
    task() async {
      await _setAutoParams(api);
      dynamic json = await _instance._net!.commonUpload(
        api,
        progress: progress,
        baseUrl: baseUrl,
        contentType: contentType,
      );
      return await _instance._commonNetBuilder!.reduceJson(json);
    }

    if (reduceError) return await _doNet(task);
    return await task();
  }

  static Future<dynamic> download(
    CommonDownloadApi api, {
    CommonProgress? progress,
    bool reduceError = true,
    String? baseUrl,
    String? contentType,
  }) async {
    task() async {
      await _setAutoParams(api);
      return await _instance._net!.commonDownload(
        api,
        progress: progress,
        baseUrl: baseUrl,
        contentType: contentType,
      );
    }

    if (reduceError) return await _doNet(task);
    return await task();
  }
}

extension ExCommonApi on CommonApi {
  Future<dynamic> get({String? baseUrl, String? contentType}) async {
    return await CommonNet.get(this, baseUrl: baseUrl, contentType: contentType);
  }

  Future<dynamic> post({String? baseUrl, String? contentType}) async {
    return await CommonNet.post(this, baseUrl: baseUrl, contentType: contentType);
  }
}
